import EventEmitter from './eventemitter.js'

export interface RemainTimeData {
  days: number;
  hours: number;
  minutes: number;
  seconds: number;
  count: number;
}

export type CountdownCallback = (remainTimeData: RemainTimeData, remainTime: number) => void

enum CountdownStatus {
  running,
  paused,
  stoped
}

export enum CountdownEventName {
  START = 'start',
  STOP = 'stop',
  RUNNING = 'running',
}

interface CountdownEventMap {
  [CountdownEventName.START]: [];
  [CountdownEventName.STOP]: [];
  [CountdownEventName.RUNNING]: [RemainTimeData, number]
}

export function fillZero(num: number) {
  return `0${num}`.slice(-2)
}

export class Countdown extends EventEmitter<CountdownEventMap> {

  private static COUNT_IN_MILLISENCOND: number = 1 * 100;
  private static SECOND_IN_MILLISENCOND: number = 10 * Countdown.COUNT_IN_MILLISENCOND;
  private static MINUTE_IN_MILLISENCOND: number = 60 * Countdown.SECOND_IN_MILLISENCOND;
  private static HOUR_IN_MILLISENCOND: number = 60 * Countdown.MINUTE_IN_MILLISENCOND;
  private static DAY_IN_MILLISENCOND: number = 24 * Countdown.HOUR_IN_MILLISENCOND;

  private endTime: number;
  private step: number;
  private status: CountdownStatus = CountdownStatus.stoped
  private remainTime: number = 0
  constructor(endTime: number, step: number = 1e3) {
    super()
    this.endTime = endTime
    this.step = step
    this.start()
  }

  public start() {
    this.emit(CountdownEventName.START)
    this.status = CountdownStatus.running
    this.countdown()
  }

  public stop() {
    this.emit(CountdownEventName.STOP)
    this.status = CountdownStatus.stoped
  }

  private countdown() {
    if (this.status !== CountdownStatus.running) return
    this.remainTime = Math.max(this.endTime - Date.now(), 0)
    this.emit(CountdownEventName.RUNNING, this.parseRemainTime(this.remainTime), this.remainTime)
    if (this.remainTime > 0) {
      setTimeout(() => {
        this.countdown()
      }, this.step);
    } else {
      this.stop()
    }
  }

  private parseRemainTime(remainTime: number): RemainTimeData {
    let time = remainTime
    const days = Math.floor(time / Countdown.DAY_IN_MILLISENCOND)
    time = time % Countdown.DAY_IN_MILLISENCOND
    const hours = Math.floor(time / Countdown.HOUR_IN_MILLISENCOND)
    time = time % Countdown.HOUR_IN_MILLISENCOND
    const minutes = Math.floor(time / Countdown.MINUTE_IN_MILLISENCOND)
    time = time % Countdown.MINUTE_IN_MILLISENCOND
    const seconds = Math.floor(time / Countdown.SECOND_IN_MILLISENCOND)
    time = time % Countdown.SECOND_IN_MILLISENCOND
    const count = Math.floor(time / Countdown.COUNT_IN_MILLISENCOND)
    return {
      days,
      hours,
      minutes,
      seconds,
      count
    }
  }
}